type ComponentType<T> = new (...args: any[]) => T;

class ComponentManager {
    private componentMap: Map<Function, Map<number, any>>;

    constructor() {
        this.componentMap = new Map();
    }

    /**
     * 注册一个组件类型
     * @param componentType 组件类型
     */
    registerComponent<T>(componentType: ComponentType<T>): void {
        if (!this.componentMap.has(componentType)) {
            this.componentMap.set(componentType, new Map());
        }
    }

    /**
     * 为实体添加一个组件
     * @param entityId 实体的ID
     * @param component 组件实例
     */
    addComponent<T>(entityId: number, component: T): void {
        const componentType = Object.getPrototypeOf(component).constructor;
        if (!this.componentMap.has(componentType)) {
            throw new Error(
                `Component type ${componentType.name} is not registered`,
            );
        }
        this.componentMap.get(componentType)!.set(entityId, component);
    }

    /**
     * 获取实体的组件
     * @param entityId 实体的ID
     * @param componentType 组件类型
     * @returns 组件实例，如果不存在则返回undefined
     */
    getComponent<T>(
        entityId: number,
        componentType: ComponentType<T>,
    ): T | undefined {
        return this.componentMap.get(componentType)?.get(entityId);
    }

    /**
     * 删除实体的组件
     * @param entityId 实体的ID
     * @param componentType 组件类型
     */
    removeComponent<T>(
        entityId: number,
        componentType: ComponentType<T>,
    ): void {
        this.componentMap.get(componentType)?.delete(entityId);
    }

    /**
     * 获取所有具有指定组件类型的实体ID
     * @param componentType 组件类型
     * @returns 实体ID数组
     */
    getEntitiesWithComponent<T>(
        componentType: ComponentType<T>,
    ): number[] {
        return Array.from(
            this.componentMap.get(componentType)?.keys() || [],
        );
    }

    /**
     * 获取所有具有指定组件类型的实体ID
     * @param componentTypes 组件类型数组
     * @returns 实体ID数组
     */
    getEntitiesWithComponents<T>(
        componentTypes: ComponentType<T>[],
    ): number[] {
        let entities = new Set<number>();
        componentTypes.forEach((componentType) => {
            const componentEntities =
                this.getEntitiesWithComponent(componentType);
            if (entities.size === 0) {
                entities = new Set(componentEntities);
            } else {
                entities = new Set(
                    [...entities].filter((entityId) =>
                        componentEntities.includes(entityId),
                    ),
                );
            }
        });
        return Array.from(entities);
    }
}
